/*
  This file is part of 'Trivial chess'.

  'Trivial chess' is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  'Trivial chess' is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with 'Trivial chess'.  If not, see <http://www.gnu.org/licenses/>.
*/

/* SVN FILE: $Id$ */
/**
 * @author         $Author$
 * @version        $Rev$
 * @lastrevision   $Date$
 * @filesource     $URL$
 */

#ifndef COMABSTRACT_H_
#define COMABSTRACT_H_

#include <boost/cstdint.hpp>

template<class Enum, class Fst, class Scd, typename Int, int n>
class ComAbstract {
public:
	static const Enum NIL() {
		return Enum(Enum::COUNT);
	}
	static const Enum END() {
		return Enum(Fst::BEGIN(), Scd::END());
	}
	static const Enum REND() {
		return Enum(Fst::RBEGIN(), Scd::REND());
	}
public:
	Int toInt() const {
		return this->me2_c().scd().toInt() << n | this->me2_c().fst().toInt();
	}

	void fromInt(const Int _enum) {
		this->_scd.fromInt(_enum >> n);
		this->_fst.fromInt(_enum & ((1 << n) - 1));
	}

	Enum operator++() {
		++this->_fst;
		if ( this->_fst == Fst::END() ) {
			this->_fst = Fst::BEGIN();
			++this->_scd;
		}
		return Enum(this->me2());
	}

	Enum operator--() {
		--this->_fst;
		if ( this->_fst == Fst::REND() ) {
			this->_fst = Fst::RBEGIN();
			--this->_scd;
		}
		return Enum(this->me2());
	}

	bool operator==(const Enum num) const {
		return this->fst() == num.fst()
			&& this->scd() == num.scd();
	}

protected:
	ComAbstract<Enum, Fst, Scd, Int, n>()
		: _fst(Fst()), _scd(Scd()) {}

	explicit ComAbstract<Enum, Fst, Scd, Int, n>(const Int num)
		: _fst(Fst(num & ((1 << n)-1))),
		  _scd(Scd(num >> n)) {}

	ComAbstract<Enum, Fst, Scd, Int, n>(const Fst fst, const Scd scd)
		: _fst(fst), _scd(scd) {}

	const Fst fst() const { return this->_fst; }
	const Scd scd() const { return this->_scd; }

	void setFst(const Fst fst) {
		this->_fst = fst;
	}

	void setScd(const Scd scd) {
		this->_scd = scd;
	}
private:
	Enum& me2() { return *static_cast<Enum*>(this); }
	Enum const& me2_c() const { return *static_cast<Enum const*>(this); }
private:
	Fst _fst;
	Scd _scd;
};



#endif /* COMABSTRACT_H_ */
